#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "wblib.h"

#include "nvtfat.h"
#include "NUC900_vpost.h"
#include "NUC900_reg.h"

#define SYS_CLOCK			14318000
#define UART_BAUD_RATE		115200


/*----------------------------------------------------------------------------------------*/
/* initialization functions                                                               */
/*----------------------------------------------------------------------------------------*/
extern int	InitUsbSystem(void);
extern int  UMAS_InitUmasDriver(void);
extern INT  InitHardDisk(INT nEngineClock);
extern INT  USBKeyboardInit(void);

/*----------------------------------------------------------------------------------------*/
/* diagnostic code subroutines                                                            */
/*----------------------------------------------------------------------------------------*/
extern int diag_usbh(void);
extern INT diag_atapi(void);
extern INT diag_audio(VOID);
extern int diag_fmi(void);
extern int diag_spi(void);
extern INT emc_main(VOID);
extern INT smartcard_main(VOID);
extern INT diag_lcd(VOID);
extern INT i2c_main(VOID);
extern INT diag_uart(VOID);
extern INT diag_ps2(VOID);
extern INT diag_pci(VOID);
extern INT diag_usbd(VOID);
extern INT diag_2d(VOID);
extern INT diag_touch_screen(VOID);
extern INT diag_rtc(VOID);
extern INT diag_pwm(VOID);
extern INT diag_kpi(VOID);

/*----------------------------------------------------------------------------------------*/
/* Test item list                                                                         */
/*----------------------------------------------------------------------------------------*/
struct test_list
{
	char  	name[32];
	int 	(*diag_func)(void);
};

struct test_list  test_items_950[] =
{
	"",							NULL,
	"(1)  USB Host          ",  diag_usbh,
	"(2)  USB Device (RAM)  ",	diag_usbd,
	"(3)  Audio             ",  diag_audio,
	"(4)  FMI               ",	diag_fmi,
	"(5)  Ethernet MAC      ",	emc_main,
	"(6)  UART              ",	diag_uart,
	"(7)  SPI               ",  diag_spi,
	"(8)  LCD               ",	diag_lcd,
	"(9)  Touch Panel       ",	diag_touch_screen
};


struct test_list  test_items_960[] =
{
	"",							NULL,
	"(1)  USB Host          ",  diag_usbh,
	"(2)  USB Device (RAM)  ",  diag_usbd,
	"(3)  PCI               ",	diag_pci,
	"(4)  Ethernet MAC      ",	emc_main,
	"(5)  UART              ",	diag_uart,
	"(6)  I2C               ",	i2c_main,
	"(7)  SPI               ",	diag_spi
};


int  get_item_number(int max)
{
	CHAR 	pcString[16];
	CHAR    chr;
	INT		nCount;

	nCount = 0;

	while (1)
	{
		chr = sysGetChar();
		if (chr == 0)               /* control character pressed */
		{
			chr = sysGetChar();
			if (chr == 0x4b)        /* left arrow key */
			{
				if (nCount > 0)      /* have characters in pcString */
				{
					nCount--;        /* delete a character */
					sysprintf("%c%c%c", 0x08, 0x20, 0x08);
				}
			}
		}
		else if (chr == 0x08)       /* backspace */
		{
			if (nCount > 0)          /* have characters in pcString */
			{
				nCount--;            /* delete a character */
				sysprintf("%c%c%c", 0x08, 0x20, 0x08);
			}
		}
		else if (chr == 10)
			;
		else
		{
			if (chr == 0xd)
			{
				int  idx;
				
				if (nCount == 1)
				{
					idx = pcString[0] - '0';
					if ((idx >= 0) && (idx < max))
						return idx;
				}
				if (nCount == 2)
				{
					idx = (pcString[0] - '0') * 10 + (pcString[1] - '0');
					if ((idx >= 0) && (idx < max))
						return idx;
				}
				return -1;
			}
		  
			sysprintf("%c", chr);
			pcString[nCount] = chr;            // read in a character
			if (nCount < 3)
				nCount++;
			else
				sysprintf("%c%c%c", 0x08, 0x20, 0x08);
		}
	}
}



int main()
{
    WB_UART_T 			uart;
	WB_PLL_T 			sysClock;
	struct test_list	*test_items;
	INT					item_len, idx;
	INT					i;
	LCDFORMATEX 		lcdformatex;

	/* CACHE_ON	*/
	sysInvalidCache();
	sysEnableCache(CACHE_WRITE_BACK);

	sysClock.pll0 = PLL_200MHZ;				//PLL0 output clock
	sysClock.pll1 = PLL_100MHZ;				//PLL1 output clock
	sysClock.cpu_src = CPU_FROM_PLL0;		//Select CPU clock source
	sysClock.ahb_clk = AHB_CPUCLK_1_2;		//Select AHB clock divider
	sysClock.apb_clk = APB_AHB_1_2;			//Select APB clock divider
	sysSetPLLConfig(&sysClock);				//Call system function call

	//outpw(REG_MFSEL, inpw(REG_MFSEL) | 0x100);
    uart.uiFreq = SYS_CLOCK;
    uart.uiBaudrate = UART_BAUD_RATE;
    uart.uiDataBits = WB_DATA_BITS_8;
    uart.uiStopBits = WB_STOP_BITS_1;
    uart.uiParity = WB_PARITY_NONE;
    uart.uiRxTriggerLevel = LEVEL_1_BYTE;
    sysInitializeUART(&uart);
	sysprintf("UART initialized\n");
	/*--- init timer ---*/
	sysSetTimerReferenceClock (TIMER0, SYS_CLOCK);
	sysStartTimer(TIMER0, 100, PERIODIC_MODE);
	
	if ((inpw(REG_PDID) & 0xfff) == 0x910)
	{
		test_items = test_items_950;
		item_len   = sizeof(test_items_950) / sizeof(struct test_list);
	}
	else
	if ((inpw(REG_PDID) & 0xfff) == 0x960)
	{
		test_items = test_items_960;
		item_len   = sizeof(test_items_960) / sizeof(struct test_list);
	}
	else
	{
		sysprintf("Not NUC950 or NUC960!!\n");
		exit(0);
	}

	fsInitFileSystem();
	InitUsbSystem();       
	UMAS_InitUmasDriver();
	
	lcdformatex.ucVASrcFormat = VA_SRC_RGB565;
    vpostLCMInit(&lcdformatex);

	while (1)
	{
		sysprintf("\n\n\n\n");

		/*--------------------------------------------------------------------------------*/
		/* print list test items                                                          */
		/*--------------------------------------------------------------------------------*/
		sysprintf("+----------------------------------+\n");
		sysprintf("|  NUC950 test items               |\n");
		sysprintf("+----------------------------------+\n");
		for (i = 1; i < item_len; i++)
			sysprintf("| %s          |\n", test_items[i].name);
		sysprintf("+----------------------------------+\n");
		
		sysprintf("\nPlease select the test item: ");
		idx = get_item_number(item_len);
		if (idx < 0)
			continue;
			
		sysprintf("\nSelect test item %d\n\n\n", idx);
		
		if (test_items[idx].diag_func != NULL)
			test_items[idx].diag_func();
		else
		{
			sysprintf("\n\n\n%s diagnostic code not available!\n", test_items[idx].name);
		}
		sysprintf("\n\nPress any key to continue...\n");
		sysGetChar();
	}
	return 0;
}


/*
 * standalone.c - minimal bootstrap for C library
 * Copyright (C) 2000 ARM Limited.
 * All rights reserved.
 */

/*
 * RCS $Revision: 1 $
 * Checkin $Date: 09/02/24 1:42p $ 0
 * Revising $Author: Ychuang3 $
 */

/*
 * This code defines a run-time environment for the C library.
 * Without this, the C startup code will attempt to use semi-hosting
 * calls to get environment information.
 */
 extern unsigned int Image$$ZI$$Limit;

void _sys_exit(int return_code)
{
label:  goto label; /* endless loop */
}

void _ttywrch(int ch)
{
    char tempch = (char)ch;
    (void)tempch;
}


__value_in_regs struct R0_R3 {unsigned heap_base, stack_base, heap_limit, stack_limit;} 
    __user_initial_stackheap(unsigned int R0, unsigned int SP, unsigned int R2, unsigned int SL)
{
    struct R0_R3 config;

    //config.heap_base = 0x00060000;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
    config.stack_base = 0x800000; //Stack base;

/*
To place heap_base directly above the ZI area, use:
    extern unsigned int Image$$ZI$$Limit;
    config.heap_base = (unsigned int)&Image$$ZI$$Limit;
(or &Image$$region_name$$ZI$$Limit for scatterloaded images)

To specify the limits for the heap & stack, use e.g:
    config.heap_limit = SL;
    config.stack_limit = SL;
*/

    return config;
}

/* end of file standalone.c */

